-------------------------------------------------------------------------------
-- FILE: fir.vhd
-- DESCRIPTION: This entity is the actual FIR-filter. Please fill the
-- architecture with your code. Use the components from components_pack
-- and constants provided in the package fir_pack.
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use work.fir_pack.all;
use work.components_pack.all;

entity fir is
	port(
		clk, rst : in  std_logic;
		x        : in  std_logic_vector(INPUT_WIDTH - 1 downto 0);
		y        : out std_logic_vector(OUTPUT_WIDTH - 1 downto 0));

end fir;

architecture structural of fir is

	-- SIGNAL DEFINITIONS HERE IF NEEDED

	type array_dffOut is array (14 downto 0) of STD_LOGIC_VECTOR(22 downto 0);
	type array_AddOut is array (14 downto 0) of STD_LOGIC_VECTOR(29 downto 0);
	signal dffOut   : array_dffOut;
	signal addOut   : array_AddOut;
	signal mult0Out : STD_LOGIC_VECTOR(29 downto 0);

	signal x_in : STD_LOGIC_VECTOR(22 downto 0);

	-- Signals for pipeline
	component tap
		generic(nr : integer);
		port(clk, rst : in  STD_LOGIC;
			 x_in     : in  STD_LOGIC_VECTOR(22 downto 0);
			 add_in   : in  STD_LOGIC_VECTOR(29 downto 0);
			 dff_out  : out STD_LOGIC_VECTOR(22 downto 0);
			 add_out  : out STD_LOGIC_VECTOR(29 downto 0));
	end component tap;

	signal pipe_to_dff : STD_LOGIC_VECTOR(22 downto 0);
	signal pipe_to_add : STD_LOGIC_VECTOR(29 downto 0);

begin                                   -- structural
	x_in <= "00000000000000000000000" + x;
	-------------------------------------------------------------------------------
	-- DIRECT FORM
	-------------------------------------------------------------------------------
	direct_form : if STRUCTURE = DIRECT generate
		first_multiplier : component fixed_mult_comb
			generic map(w            => x_in'length,
				        w_m          => COEFF_WIDTH,
				        multiplicand => -1)
			port map(input  => x_in,
				     output => mult0Out);

		gen_taps : for i in 0 to 14 generate
			first_tap_if : if i = 0 generate
				first_tap : tap
					generic map(nr => i)
					port map(clk     => clk,
						     rst     => rst,
						     x_in    => x_in,
						     add_in  => mult0Out,
						     dff_out => dffOut(i),
						     add_out => addOut(i));

			end generate first_tap_if;
			last_tap_if : if i = 14 generate
				last_tap : tap
					generic map(
						nr => i
					) port map(
						clk => clk,
						rst => rst,
						x_in => dffOut(i - 1),
						add_in => addOut(i - 1),
						dff_out => dffOut(i),
						add_out => y
					);
			end generate last_tap_if;
			rest_tap_if : if i > 0 and i < 14 generate
				rest_tap : tap
					generic map(
						nr => i
					)
					port map(
						clk     => clk,
						rst     => rst,
						x_in    => dffOut(i - 1),
						add_in  => addOut(i - 1),
						dff_out => dffOut(i),
						add_out => addOut(i)
					);
			end generate rest_tap_if;
		end generate gen_taps;

	-- DEVELOPE YOUR CODE HERE FOR THE FIR FILTER IN DIRECT FORM

	end generate direct_form;

	-------------------------------------------------------------------------------
	-- PIPELINED FORM
	-------------------------------------------------------------------------------
	pipelined_form : if STRUCTURE = PIPELINED generate
		first_multiplier : component fixed_mult_comb
			generic map(w            => x_in'length,
				        w_m          => COEFF_WIDTH,
				        multiplicand => -1)
			port map(input  => x_in,
				     output => mult0Out);

		gen_taps : for i in 0 to 14 generate
			first_tap_if : if i = 0 generate
				first_tap : tap
					generic map(nr => i)
					port map(clk     => clk,
						     rst     => rst,
						     x_in    => x_in,
						     add_in  => mult0Out,
						     dff_out => dffOut(i),
						     add_out => addOut(i));

			end generate first_tap_if;

			rest_tap_if : if i > 0 and i < 14 and i /= 8 generate
				rest_tap : tap
					generic map(
						nr => i
					)
					port map(
						clk     => clk,
						rst     => rst,
						x_in    => dffOut(i - 1),
						add_in  => addOut(i - 1),
						dff_out => dffOut(i),
						add_out => addOut(i)
					);
			end generate rest_tap_if;

			pipe_tap_if : if i = 8 generate
				dff_to_dff : component dff
					generic map(w => x_in'length)
					port map(clk => clk,
						     rst => rst,
						     d   => dffOut(i - 1),
						     q   => pipe_to_dff);
				dff_to_add : component dff
					generic map(w => 30)
					port map(clk => clk,
						     rst => rst,
						     d   => addOut(i - 1),
						     q   => pipe_to_add);

				pipetap : tap
					generic map(
						nr => i
					)
					port map(
						clk     => clk,
						rst     => rst,
						x_in    => pipe_to_dff,
						add_in  => pipe_to_add,
						dff_out => dffOut(i),
						add_out => addOut(i)
					);
					end generate pipe_tap_if;

				last_tap_if : if i = 14 generate
					last_tap : tap
						generic map(
							nr => i
						) port map(
							clk => clk,
							rst => rst,
							x_in => dffOut(i - 1),
							add_in => addOut(i - 1),
							dff_out => dffOut(i),
							add_out => y
						);
				end generate last_tap_if;

			end generate gen_taps;

		end generate pipelined_form;

	end structural;

